package controllers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"unicode"
	"gouniapp/configs"
	"github.com/gin-gonic/gin"
	"github.com/patrickmn/go-cache"
	"github.com/xuri/excelize/v2"
)

// 请求结构体
type FirstRequest struct {
	RedisKey string                 `json:"rediskey"`
	Bm       string                 `json:"bm"`
	Url      string                 `json:"url"`
	Max      int                    `json:"max"`
	Zd       map[string]interface{} `json:"zd"`
}

// 处理创建请求
func HandleCreateRequest(ctx *gin.Context) {
	var data FirstRequest
	if err := ctx.ShouldBindJSON(&data); err != nil {
		sendErrorResponse(ctx, 1, err.Error())
		return
	}

	if data.RedisKey == "" || data.Url == "" {
		sendErrorResponse(ctx, 1, "参数不完整")
		return
	}

	if data.Max == 0 {
		sendErrorResponse(ctx, 1, "数据为空")
		return
	}

	// 检查任务是否已存在
	if _, found := configs.CRdb.Get(data.RedisKey); found {
		sendErrorResponse(ctx, 1, "任务已存在")
		return
	}

	go asyncGenerateExcel(data)
	ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "创建任务成功", "result": data.RedisKey})
}

// 异步生成Excel
func asyncGenerateExcel(data FirstRequest) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("Panic in asyncGenerateExcel: %v", r)
			configs.CRdb.Set(data.RedisKey+"_error", "内部错误", cache.DefaultExpiration)
		}
	}()

	startTime := time.Now()
	defer func() {
		log.Printf("Excel生成完成，耗时: %v", time.Since(startTime))
	}()

	// 初始化进度
	configs.CRdb.Set(data.RedisKey+"_max", data.Max, cache.NoExpiration)
	configs.CRdb.Set(data.RedisKey, 0, cache.DefaultExpiration)

	// 生成安全文件名
	safeName := sanitizeFilename(data.RedisKey) + ".xlsx"
	filePath := filepath.Join("uploads", "excel", safeName)

	// 创建Excel文件
	if err := generateExcelFile(data, filePath); err != nil {
		configs.CRdb.Set(data.RedisKey+"_error", err.Error(), cache.DefaultExpiration)
	}
}

// 生成Excel文件
func generateExcelFile(data FirstRequest, filePath string) error {
	file := excelize.NewFile()
	defer func() {
		if err := file.Close(); err != nil {
			log.Printf("文件关闭失败: %v", err)
		}
	}()

	streamWriter, err := file.NewStreamWriter("Sheet1")
	if err != nil {
		return fmt.Errorf("创建流式写入器失败: %w", err)
	}

	// 设置列宽（添加调试信息）
	if err := streamWriter.SetColWidth(1, len(data.Zd), 12); err != nil {
		return fmt.Errorf("设置列宽失败(列数%d): %w", len(data.Zd), err)
	}

	// 写入表头（添加调试信息）
	if err := writeHeader(streamWriter, data.Zd); err != nil {
		return fmt.Errorf("写入表头失败: %w", err)
	}

	// 写入数据（添加调试信息）
	if err := writeDataRows(streamWriter, data, filePath); err != nil {
		return fmt.Errorf("写入数据失败: %w", err)
	}

	// 必须刷新流写入器（关键修复）
	if err := streamWriter.Flush(); err != nil {
		return fmt.Errorf("流写入器刷新失败: %w", err)
	}

	// 保存文件（添加调试信息）
	if err := file.SaveAs(filePath); err != nil {
		return fmt.Errorf("文件保存失败[路径:%s]: %w", filePath, err)
	}

	return nil
}

// 写入表头
func writeHeader(sw *excelize.StreamWriter, zd map[string]interface{}) error {
	headers := make([]interface{}, len(zd))
	for i := 0; i < len(zd); i++ {
		headers[i] = zd["k"+strconv.Itoa(i)]
	}

	cell, _ := excelize.CoordinatesToCellName(1, 1)
	return sw.SetRow(cell, headers, excelize.RowOpts{Height: 20})
}

// 写入数据行
func writeDataRows(sw *excelize.StreamWriter, data FirstRequest, filePath string) error {
	currentRow := 2
	pageSize := 600
	totalPages := (data.Max + pageSize - 1) / pageSize

	for currentPage := 1; currentPage <= totalPages; currentPage++ {
		records, err := fetchDataFromAPI(data.Url, data.Bm, data.Zd, currentPage, pageSize)
		if err != nil {
			return fmt.Errorf("数据获取失败: %w", err)
		}

		for _, record := range records {
			if err := writeRecord(sw, currentRow, record); err != nil {
				return err
			}

			// 更新进度
			configs.CRdb.Set(data.RedisKey, currentRow, cache.DefaultExpiration)
			currentRow++
		}
	}
	return nil
}

// 获取数据
func fetchDataFromAPI(url, bm string, zd map[string]interface{}, page, pageSize int) ([]map[string]interface{}, error) {
    log.Printf("请求API: %s 页码: %d 页大小: %d", url, page, pageSize)
	client := &http.Client{Timeout: 30 * time.Second}
	requestBody := map[string]interface{}{
		"bm":       bm,
		"keys":     getOrderedKeys(zd),
		"page":     page,
		"pagesize": pageSize,
	}

	jsonData, _ := json.Marshal(requestBody)
	resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("API请求失败: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("API返回错误状态码: %d", resp.StatusCode)
	}

	var result []map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("响应解析失败: %w", err)
	}
    //log.Printf("API响应: %s", result)
	return result, nil
}

// 获取有序键列表
func getOrderedKeys(zd map[string]interface{}) []string {
	keys := make([]string, len(zd))
	for i := 0; i < len(zd); i++ {
		keys[i] = "k" + strconv.Itoa(i)
	}
	return keys
}

// 写入单条记录
func writeRecord(sw *excelize.StreamWriter, rowNum int, record map[string]interface{}) error {
	rowData := make([]interface{}, len(record))
	for i := 0; i < len(record); i++ {
		key := "k" + strconv.Itoa(i)
		value, exists := record[key]
		if !exists {
			return fmt.Errorf("缺少关键字段%s", key)
		}
		// 处理不同类型数据
		switch v := value.(type) {
		case time.Time:
			value = v.Format("2006-01-02 15:04:05")
		case nil:
			value = ""
		}
		rowData[i] = value
	}
	cell, _ := excelize.CoordinatesToCellName(1, rowNum)
	return sw.SetRow(cell, rowData, excelize.RowOpts{Height: 18})
}

// 安全文件名处理
func sanitizeFilename(key string) string {
	return strings.Map(func(r rune) rune {
		if unicode.IsLetter(r) || unicode.IsNumber(r) || r == '-' || r == '_' {
			return r
		}
		return -1
	}, key)
}

// 查询进度
func HandleProgressQuery(ctx *gin.Context) {
	redisKey := ctx.Param("rediskey")
	
	// 获取当前进度
	current, total, err := getProgress(redisKey)
	if err != nil {
		sendErrorResponse(ctx, 1, err.Error())
		return
	}

	// 计算进度百分比
	progress := 0
	if total > 0 {
		progress = current * 100 / total
	}

	// 处理完成情况
	if progress >= 100 {
		handleCompletion(ctx, redisKey)
		return
	}

	ctx.JSON(http.StatusOK, gin.H{"code": 0, "jd": progress, "message": "正在导出"})
}

// 获取进度信息
func getProgress(redisKey string) (int, int, error) {
	currentVal, found := configs.CRdb.Get(redisKey)
	if !found {
		return 0, 0, fmt.Errorf("任务不存在")
	}

	current, ok := currentVal.(int)
	if !ok {
		return 0, 0, fmt.Errorf("无效的进度类型")
	}

	maxVal, found := configs.CRdb.Get(redisKey + "_max")
	if !found {
		return 0, 0, fmt.Errorf("任务配置丢失")
	}

	total, ok := maxVal.(int)
	if !ok {
		return 0, 0, fmt.Errorf("无效的总数类型")
	}

	return current, total, nil
}

// 处理完成情况
func handleCompletion(ctx *gin.Context, redisKey string) {
	safeName := sanitizeFilename(redisKey) + ".xlsx"
	filePath := filepath.Join("uploads", "excel", safeName)

	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		sendErrorResponse(ctx, 1, "文件生成延迟")
		return
	}

	cleanupTask(redisKey)
	ctx.JSON(http.StatusOK, gin.H{
		"code":   200,
		"result": configs.MyURL + filepath.ToSlash(filePath), // 统一路径格式
	})
}

// 清理任务
func cleanupTask(key string) {
	configs.CRdb.Delete(key)
	configs.CRdb.Delete(key + "_max")
	configs.CRdb.Delete(key + "_error")
}

// 通用错误响应
func sendErrorResponse(ctx *gin.Context, code int, message string) {
	ctx.JSON(http.StatusOK, gin.H{
		"code":    code,
		"message": message,
		"result":  nil,
	})
}